package Compiler;

import Data.*;

/**
 * the parser of compiler
 * 
 * @author Bing
 * 
 */
public class Parser {

	/*
	 * CREATE DATABASE id ; USE ID ; CREATE TABLE id ( id dt , id dt , ... ) ;
	 * INSERT INTO TABLE id VALUES(va,va,va...); SELECT id,id,...//or * FROM
	 * id,id... SELECT id,id,...//or * FROM id,id... WHERE EX...
	 */

	private static int[] results = null;
	private static int pointer = 0;

	/**
	 * run parser
	 */
	public static void start() {

		results = Scanner.SCANNER_RESULT;
		pointer = 0;
		int i = 0;
		String s = "";
		while (results[i] != 0) {
			s += results[i] + " ";
			i++;
		}
		//Functions.output("*" + s);

		switch (results[pointer]) {
		case 1100: // CREATE

			pointer++;
			f_create();
			break;

		case 1122: // USE
			pointer++;
			f_use();
			break;

		case 1103: // INSERT
			pointer++;
			f_insert();
			break;

		case 1108: // SELECT
			pointer++;
			Table t = f_select();
			if (t != null)
				Functions.output(t.toString());
			break;
		case 1104:
			pointer++;
			f_delete();
			break;

		default:
			Functions.output("Syntax Error!");
		}

	}
	/**
	 * DELETE ****
	 */
	private static void f_delete(){
		//Functions.output("*delete");
		if(results[pointer]!=1109){
			Functions.output("Syntax Error!");
			return;
		}
		
		pointer++;
		
		Tuple[] t = new Tuple[10];
		for (int i = 0; i < 10; i++)
			t[i] = null;
		List<Tuple[]> list = f_from(new List<Tuple[]>(), t, 0);
		
		if(list!=null){
			for(Tuple[] tu :list.getAll()){
				int i=0;
				while(tu[i]!=null){
					Functions.getTable(tu[i].getTableName()).removeTuple(tu[i]);
					i++;
				}
			}
		}
		Functions.output("deletion done");
		
		
	}

	/**
	 * SELECT ***
	 */
	private static Table f_select() {
		//Functions.output("*select");

		// SELECT id,id,...//or * FROM id,id...
		if (results[pointer] == 1009) {

			pointer++;
			if (results[pointer] != 1109) {
				Functions.output("Syntax Error!");
				return null;
			}
			pointer++;

			Tuple[] t = new Tuple[10];
			for (int i = 0; i < 10; i++)
				t[i] = null;
			List<Tuple[]> list = f_from(new List<Tuple[]>(), t, 0);

			if (list == null)
				return null;
			int i = 0;
			int s = 0;
			while (t[i] != null) {
				s += t[i].getSize();
				i++;
			}
			int[] ty = new int[s];
			String[] na = new String[s];

			s = 0;
			i = 0;
			while (t[i] != null) {
				for (int j = 0; j < t[i].getSize(); j++) {
					ty[s + j] = t[i].getTypes()[j];
				}
				for (int j = 0; j < t[i].getSize(); j++) {

					na[s] = t[i].getNames()[j];
					s++;
				}
				i++;
			}

			Table nt = new Table(null, ty, na);

			for (Tuple[] tu : list.getAll()) {
				i = 0;
				Object[] data = new Object[s];
				s = 0;
				while (tu[i] != null) {
					for (int j = 0; j < tu[i].getSize(); j++) {
						data[s] = tu[i].getData()[j];
						s++;
					}
					i++;
				}
				nt.addTuple(new Tuple(s, data));

			}

			return nt;

		} else if (results[pointer] / 1000 == 5) {
			String[] name = new String[100];
			int s = 0;

			while (results[pointer] != 0) {
				if (results[pointer] / 1000 != 5) {

					Functions.output("Syntax Error!");
					return null;
				}
				name[s] = (String) Scanner.getValue(results[pointer]);
				s++;
				pointer++;

				if (results[pointer] == 1109) {
					break;
				}

				if (results[pointer] != 1000) {

					Functions.output("Syntax Error!");
					return null;
				}
				pointer++;
			}
			if (results[pointer] != 1109) {

				Functions.output("Syntax Error!");
				return null;
			}

			pointer++;

			int[] ty = new int[s];
			String[] na = new String[s];

			for (int i = 0; i < s; i++)
				na[i] = name[i];

			Tuple[] t = new Tuple[10];
			for (int i = 0; i < 10; i++)
				t[i] = null;
			List<Tuple[]> list = f_from(new List<Tuple[]>(), t, 0);
			if (list == null)
				return null;

			int i = 0;
			while (t[i] != null) {
				for (int j = 0; j < t[i].getSize(); j++) {
					for (int k = 0; k < s; k++) {
						if (t[i].getNames()[j].compareTo(na[k]) == 0) {
							ty[k] = t[i].getTypes()[j];
						}
					}
				}
				i++;
			}

			Table nt = new Table(null, ty, na);

			for (Tuple[] tu : list.getAll()) {
				Object[] data = new Object[s];
				i = 0;
				while (tu[i] != null) {
					for (int j = 0; j < tu[i].getSize(); j++) {
						for (int k = 0; k < s; k++) {
							if (tu[i].getNames()[j].compareTo(na[k]) == 0) {
								data[k] = tu[i].getData()[j];
							}
						}
					}
					i++;
				}

				nt.addTuple(new Tuple(s, data));
			}

			return nt;

		}

		Functions.output("Syntax Error!");
		return null;
	}

	/**
	 * FROM ***
	 * 
	 * @return a list of tuple
	 */
	private static List<Tuple[]> f_from(List<Tuple[]> list, Tuple[] tuples,
			int index) {
		// id,id...
		// id as id ...
		// ... where

		if (results[pointer] / 1000 != 5) {
			Functions.output("Syntax Error!");
			return null;
		}
		Table table = Functions.getTable((String) Scanner
				.getValue(results[pointer]));
		if (table == null) {
			Functions.output((String) Scanner.getValue(results[pointer])
					+ " not existed!");
		}
		pointer++;

		int code = results[pointer];
		pointer++;

		int record = pointer;

		for (Tuple t : table.getAll()) {
			tuples[index] = t;

			switch (code) {
			case 1000: // ,
				if (f_from(list, tuples, index + 1) == null)
					return null;
				break;
			case 1001: // ;
				list.add(tuples.clone());
				break;
			case 1110: // WHERE
				if (f_where(tuples))
					list.add(tuples.clone());
				break;
			default:
				//Functions.output(code+"");
				Functions.output("Syntax Error!");
				return null;

			}
			pointer = record;

		}
		return list;

	}

	/**
	 * WHERE ***
	 * 
	 * @return a boolean values
	 */
	private static boolean f_where(Tuple[] tuples) {
		// left
		String left = "";
		if (results[pointer] >= 2000 && results[pointer] < 5000
				&& results[pointer + 1] == 1006) {
			left = Scanner.getValue(results[pointer]).toString();
			pointer += 2;
		} else if (results[pointer] >= 5000 && results[pointer + 1] == 1006) {
			int i = 0;
			while (tuples[i] != null) {
				for (int j = 0; j < tuples[i].getSize(); j++) {
					if (tuples[i].getNames()[j].compareTo((String) Scanner
							.getValue(results[pointer])) == 0) {
						left = tuples[i].getData()[j].toString();

						break;
					}
				}
				
				i++;
			}
			pointer += 2;
		} else if (results[pointer] >= 5000 && results[pointer + 1] == 1003
				&& results[pointer + 2] >= 5000&& results[pointer + 3] == 1006) {
			int i = 0;
			while (tuples[i] != null) {
				if (tuples[i].checkName((String) Scanner
						.getValue(results[pointer]))) {
					for (int j = 0; j < tuples[i].getSize(); j++) {
						if (tuples[i].getNames()[j].compareTo(Scanner.getValue(results[pointer+2]).toString())==0) {
							left = tuples[i].getData()[j].toString();
						}
					}
				}
				i++;
			}
			pointer += 4;
		}else{
			//Functions.output("111");
			Functions.output("Syntax Error!");
			return false;
		}
		
		// right
		
		String right = "";
		if (results[pointer] >= 2000 && results[pointer] < 5000) {
			right = Scanner.getValue(results[pointer]).toString();
			pointer ++;
		} else if (results[pointer] >= 5000) {
			int i = 0;
			while (tuples[i] != null) {
				for (int j = 0; j < tuples[i].getSize(); j++) {
					if (tuples[i].getNames()[j].compareTo((String) Scanner
							.getValue(results[pointer])) == 0) {
						right = tuples[i].getData()[j].toString();

						break;
					}
				}
				
				i++;
			}
			pointer ++;
		} else if (results[pointer] >= 5000 && results[pointer + 1] == 1003
				&& results[pointer + 2] >= 5000) {
			int i = 0;
			while (tuples[i] != null) {
				if (tuples[i].checkName((String) Scanner
						.getValue(results[pointer]))) {
					for (int j = 0; j < tuples[i].getSize(); j++) {
						if (tuples[i].getNames()[j].compareTo(Scanner.getValue(results[pointer+2]).toString())==0) {
							right = tuples[i].getData()[j].toString();
						}
					}
				}
				i++;
			}
			pointer += 3;
		}else{
			//Functions.output("222!");
			Functions.output("Syntax Error!");
			return false;
		}
		if(results[pointer]==1001) return left.compareTo(right)==0;
		if(results[pointer]==1111) {
			pointer++;
			 return (left.compareTo(right)==0) && f_where(tuples);
		}
		//Functions.output("333!");
		
		Functions.output("Syntax Error!");
		return false;
	}

	/**
	 * INSERT ***
	 */
	private static void f_insert() {
		//Functions.output("*INSERT");
		String name = "";
		// INTO id VALUES(
		if (results[pointer] == 1105 && results[pointer + 1] / 1000 == 5
				&& results[pointer + 2] == 1106 && results[pointer + 3] == 1004) {

			name = (String) Scanner.getValue(results[pointer + 1]);

			pointer += 4;
			boolean empty = true;
			int s = 0;
			Object[] t = new Object[100];
			int[] type = new int[100];
			while (results[pointer] != 1005) {
				empty = false;

				if (results[pointer] / 1000 > 1 && results[pointer] / 1000 < 5) { // va
					t[s] = Scanner.getValue(results[pointer]);
					//Functions.output(""+(results[pointer] / 1000) );
					switch (results[pointer] / 1000){
					case 2:
						type[s] = 1202;
						break;
					case 3:
						type[s] = 1200;
						break;
					case 4:
						type[s] = 1201;
						break;
					}
					s++;
					pointer++;
				} else {
					Functions.output("Syntax Error!");
					return;
				}
				if (results[pointer] == 1005) {// )
					pointer++;
					break;
				}
				if (results[pointer] != 1000) {// ,
					Functions.output("Syntax Error!");
					return;
				}

				pointer++;

			}
			if (empty)
				pointer++;

			if (results[pointer] != 1001) {// ;
				Functions.output("Syntax Error!");
				return;
			}
			pointer++;

			Object[] o = new Object[s];
			for (int i = 0; i < s; i++) {
				o[i] = t[i];
			}
			Functions.insert_tuple(name, o, s,type);

		} else {
			Functions.output("Syntax Error!");
			return;
		}
	}

	/**
	 * CREATE ***
	 */
	private static void f_create() {
		//Functions.output("*create");

		switch (results[pointer]) {
		case 1101: // DATABASE id ;
			//Functions.output("*database");
			pointer++;
			if (results[pointer] / 1000 == 5 && results[pointer + 1] == 1001) {
				Functions.create_database((String) Scanner
						.getValue(results[pointer]));
				pointer += 2;
			} else
				Functions.output("Syntax Error!");

			return;
		case 1102: // TABLE
			//Functions.output("*table");
			pointer++;
			if (results[pointer] / 1000 != 5) { // id
				Functions.output("Syntax Error!");
				return;
			}
			String name = (String) Scanner.getValue(results[pointer]);
			pointer++;
			if (results[pointer] != 1004) { // (
				Functions.output("Syntax Error!");
				return;
			}
			pointer++;

			int[] tt = new int[100];
			String[] nt = new String[100];
			int s = 0;
			boolean empty = true;
			while (results[pointer] != 1005) { // )
				empty = false;
				if (results[pointer] == 0) {
					Functions.output("Syntax Error!");
					return;
				}
				if (results[pointer] / 1000 == 5
						&& results[pointer + 1] / 100 == 12) {
					tt[s] = results[pointer + 1];
					nt[s] = (String) Scanner.getValue(results[pointer]);
					s++;
					pointer += 2;
				} else {
					Functions.output("Syntax Error!");
					return;
				}
				if (results[pointer] == 1005) {// )
					pointer++;
					break;
				}
				if (results[pointer] != 1000) { // ,
					Functions.output("Syntax Error!");
					return;
				}
				pointer++;

			}
			if (empty)
				pointer++;
			if (results[pointer] != 1001) { // ;
				Functions.output("Syntax Error!");
				return;
			}
			pointer++;

			int[] ty = new int[s];
			String[] na = new String[s];
			for (int i = 0; i < s; i++) {
				ty[i] = tt[i];
				na[i] = nt[i];
			}
			Functions.create_table(name, ty, na);
			return;

		default:
			Functions.output("Syntax Error!");
		}
	}

	/**
	 * USE ***
	 */
	private static void f_use() {

		//Functions.output("*use");
		if (results[pointer] / 1000 == 5 && results[pointer + 1] == 1001) {
			Functions.change_database((String) Scanner
					.getValue(results[pointer]));
			pointer += 2;
		} else
			Functions.output("Syntax Error!");

	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
